package 并发编程.转账加锁避免死锁.service;

import 并发编程.转账加锁避免死锁.UserAccount;

import java.util.Random;

/**
 * 类说明：不会产生死锁的安全转账第二种方法，尝试拿锁
 * 活锁：两个线程太谦让了，都尝试拿锁，第二个线程拿锁，第一个会释放，会导致一直拿锁释放锁，
 * 故 需要在休眠一个随机数，来避免两个锁都没获取到，导致活锁
 *
 */
public class SafeOperateToo implements ITransfer {

    @Override
    public void transfer(UserAccount from, UserAccount to, int amount)
            throws InterruptedException {
        Random r = new Random();
        while (true) {
            if (from.getLock().tryLock()) {
                try {
                    System.out.println(Thread.currentThread().getName()
                            + " get " + from.getName());
                    if (to.getLock().tryLock()) {
                        try {
                            System.out.println(Thread.currentThread().getName()
                                    + " get " + to.getName());
                            //两把锁都拿到了
                            from.flyMoney(amount);
                            to.addMoney(amount);
                            break;
                        } finally {
                            to.getLock().unlock();
                        }
                    }
                } finally {
                    from.getLock().unlock();
                }
            }
            // 由于是活锁 错开两个线程获取锁的时间
          Thread.sleep(r.nextInt(10));
        }
    }
}
